package com.jdk.demo.nio.bilibili.Maodun.net.qiujuer2.library.clink.impl.async;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer2.library.clink.core.IoArgs;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer2.library.clink.core.ReceiveDispatcher;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer2.library.clink.core.ReceivePacket;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer2.library.clink.core.Receiver;
import com.jdk.demo.nio.bilibili.Maodun.net.qiujuer2.library.clink.utils.CloseUtils;

public class AsyncReceiveDispatcher implements ReceiveDispatcher, IoArgs.IoArgsEventProcessor, AsyncPacketWriter.PacketProvider {

	private final AtomicBoolean isClosed =  new AtomicBoolean(false);
	private final Receiver receiver;
	private final ReceivePacketCallback callBack;

	private final AsyncPacketWriter writer = new AsyncPacketWriter(this);

	public AsyncReceiveDispatcher(Receiver receiver, ReceivePacketCallback callBack) throws IOException {
		this.receiver = receiver;
		this.receiver.setReceiveListener(this);
		this.callBack = callBack;
	}

	@Override
	public void start() {
		registerReceive();
	}

	private void registerReceive() {
		try {
			receiver.postReceiveAsync();
		} catch (IOException e) {
			closeAndNotify();
		}
	}

	private void closeAndNotify() {
		CloseUtils.close(this);
	}

	@Override
	public void stop() {

	}

	@Override
	public void close() throws IOException {
		if(isClosed.compareAndSet(false, true)) {
			writer.close();
		}
	}

	/**
     * 网络接收就绪，此时可以读取数据，需要返回一个容器用于容纳数据
     *
     * @return 用以容纳数据的IoArgs
     */
    @Override
    public IoArgs provideIoArgs() {
        IoArgs ioArgs = writer.takeIoArgs();
        // 一份新的IoArgs需要调用一次开始写入数据的操作
        ioArgs.startWriting();
        return ioArgs;
    }

	@Override
	public void onConsumeFailed(IoArgs args, Exception e) {
		e.printStackTrace();
	}

	/**
     * 接收数据成功
     *
     * @param args IoArgs
     */
    @Override
    public void onConsumeCompleted(IoArgs args) {
        if (isClosed.get()) {
            return;
        }

        // 消费数据之前标示args数据填充完成，
        // 改变未可读取数据状态
        args.finishWriting();

        // 有数据则重复消费
        do {
            writer.consumeIoArgs(args);
        } while (args.remained() && !isClosed.get());
        registerReceive();
    }

	@Override
	public ReceivePacket takePacket(byte type, long length, byte[] headerInfo) {
		return callBack.onArrivedNewPacket(type, length);
	}

	@Override
	public void completedPacket(ReceivePacket packet, boolean isSucceed) {
		CloseUtils.close(packet);
		callBack.onReceivePacketComplated(packet);
	}

}
